#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>


static struct pci_device_id ids[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3), },
	{ PCI_DEVICE(0x1af4, 0x1000), }, /*virtio net*/
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, ids);

static unsigned char skel_get_revision(struct pci_dev *dev)
{
	int32_t ret = ~0;

	u8 revision;
	u16 verdor_id;
	u16 dev_id;
	
	unsigned long res_start;
	unsigned long res_end;
	ulong res_flag;

	u8 myirqpin;
	u8 myirq;

	pci_read_config_byte(dev, PCI_REVISION_ID, &revision);
	printk(KERN_WARNING "skel_get_revision revision: 0x%x\n", revision);

	pci_read_config_word(dev, PCI_VENDOR_ID, &verdor_id);
	printk(KERN_WARNING "skel_get_revision verdor_id: 0x%x\n", verdor_id);

	pci_read_config_word(dev, PCI_DEVICE_ID, &dev_id);
	printk(KERN_WARNING "skel_get_revision dev_id: 0x%x\n", dev_id);

	res_start = pci_resource_start(dev, 0x0);
	res_end = pci_resource_end(dev, 0x0);
	res_flag = pci_resource_flags(dev, 0x0);
	printk(KERN_WARNING "skel_get_revision bar 0x0 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);
	
	res_start = pci_resource_start(dev, 0x1);
	res_end = pci_resource_end(dev, 0x1);
	res_flag = pci_resource_flags(dev, 0x1);
	printk(KERN_WARNING "skel_get_revision bar 0x1 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);

	res_start = pci_resource_start(dev, 0x2);
	res_end = pci_resource_end(dev, 0x2);
	res_flag = pci_resource_flags(dev, 0x2);
	printk(KERN_WARNING "skel_get_revision bar 0x2 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);

	res_start = pci_resource_start(dev, 0x3);
	res_end = pci_resource_end(dev, 0x3);
	res_flag = pci_resource_flags(dev, 0x3);
	printk(KERN_WARNING "skel_get_revision bar 0x3 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);

	res_start = pci_resource_start(dev, 0x4);
	res_end = pci_resource_end(dev, 0x4);
	res_flag = pci_resource_flags(dev, 0x4);
	printk(KERN_WARNING "skel_get_revision bar 0x4 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);

	res_start = pci_resource_start(dev, 0x5);
	res_end = pci_resource_end(dev, 0x5);
	res_flag = pci_resource_flags(dev, 0x5);
	printk(KERN_WARNING "skel_get_revision bar 0x5 resource start: 0x%lx, end: 0x%lx, flag: 0x%lx\n", res_start, res_end, res_flag);

	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &myirqpin);
	if(myirqpin){
		ret = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq);
		if(ret){
			printk(KERN_ERR "PCI_INTERRUPT_LINE read error feng\n");
		} else {
			printk(KERN_WARNING "skel_get_revision myirqpin 0x%x, myirq: 0x%x\n", myirqpin, myirq);
		}
	} else {
		printk(KERN_WARNING "no irq pin\n");
	}



	return revision;
}

static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	printk(KERN_WARNING "probe & enable device feng\n");
	/* Do probing type stuff here.  
	 * Like calling request_region();
	 */
	pci_enable_device(dev);
	
	if (skel_get_revision(dev) == 0x42)
		return -ENODEV;


	return 0;
}

static void remove(struct pci_dev *dev)
{
	/* clean up any allocated resources and stuff here.
	 * like call release_region();
	 */
	printk(KERN_WARNING "remove feng\n");
}

static struct pci_driver pci_driver = {
	.name = "pci_skel",
	.id_table = ids,
	.probe = probe,
	.remove = remove,
};

static int __init pci_skel_init(void)
{
	printk(KERN_WARNING "pci_skel_init register pci feng \n");
	return pci_register_driver(&pci_driver);
}

static void __exit pci_skel_exit(void)
{
	printk(KERN_WARNING "pci_skel_exit unregister pci feng \n");
	pci_unregister_driver(&pci_driver);
}

MODULE_LICENSE("GPL");

module_init(pci_skel_init);
module_exit(pci_skel_exit);
